/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openFuyao is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

// Package clean 执行具体的清理工作
package clean

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"env-check/pkg/config"
	"env-check/pkg/logger"
)

// FileCleaner 文件清理器
type FileCleaner struct {
	config *config.AppConfig
	logger *logger.Logger
}

// NewCleaner 创建新的清理器
func NewCleaner(cfg *config.AppConfig, log *logger.Logger) *FileCleaner {
	return &FileCleaner{
		config: cfg,
		logger: log,
	}
}

// Execute 执行文件清理
func (c *FileCleaner) Execute() (*config.CleanResult, error) {
	c.logger.Info("start clean file ......")
	c.logger.Info(fmt.Sprintf("path(s) to be cleaned up: %v", c.config.Paths))

	if c.config.CleanDryRun {
		c.logger.Warning("simulated clean mode - does not actually delete files")
	}

	result := &config.CleanResult{
		Timestamp: time.Now(),
		Deleted:   make([]config.FileInfo, 0),
		Failed:    make([]config.FileInfo, 0),
		Skipped:   make([]config.FileInfo, 0),
		Summary:   config.CleanSummary{},
	}

	// 清理所有路径
	for _, path := range c.config.Paths {
		c.cleanPath(path, result)
	}

	// 更新汇总信息
	result.Summary.TotalChecked = len(c.config.Paths)
	result.Summary.TotalDeleted = len(result.Deleted)
	result.Summary.TotalFailed = len(result.Failed)
	result.Summary.TotalSkipped = len(result.Skipped)

	c.logger.Info("file clean completed")
	return result, nil
}

// cleanPath 清理单个路径
func (c *FileCleaner) cleanPath(path string, result *config.CleanResult) {
	absPath, err := filepath.Abs(path)
	if err != nil {
		fileInfo := config.FileInfo{
			Path:  path,
			Error: fmt.Sprintf("unable to obtain the absolute path: %v", err),
		}
		result.Failed = append(result.Failed, fileInfo)
		c.logger.Error(fmt.Sprintf("deldete failed: %s - %v", path, err))
		return
	}

	// 检查路径是否存在
	info, err := os.Lstat(absPath)
	if err != nil {
		c.dealLstatError(err, absPath, result)
		return
	}

	fileInfo := config.FileInfo{
		Path:        absPath,
		Exists:      true,
		IsDir:       info.IsDir(),
		Permissions: info.Mode().String(),
	}

	// 询问用户确认（如果需要）
	if !c.shouldDelete(fileInfo) {
		result.Skipped = append(result.Skipped, fileInfo)
		c.logger.Info(fmt.Sprintf("user skip delete: %s", absPath))
		return
	}

	// 执行删除
	if err := c.deletePath(fileInfo); err != nil {
		fileInfo.Error = err.Error()
		result.Failed = append(result.Failed, fileInfo)
		c.logger.Error(fmt.Sprintf("delete failed: %s - %v", absPath, err))
	} else {
		result.Deleted = append(result.Deleted, fileInfo)
		if c.config.CleanDryRun {
			c.logger.Info(fmt.Sprintf("Simulated delete: %s", absPath))
		} else {
			c.logger.Success(fmt.Sprintf("delete successfully: %s", absPath))
		}
	}
}

func (c *FileCleaner) dealLstatError(err error, absPath string, result *config.CleanResult) {
	if os.IsNotExist(err) {
		fileInfo := config.FileInfo{
			Path:   absPath,
			Exists: false,
			Error:  "path does not exist",
		}
		result.Skipped = append(result.Skipped, fileInfo)
		c.logger.Info(fmt.Sprintf("skip non-existent path: %s", absPath))
		return
	}

	fileInfo := config.FileInfo{
		Path:  absPath,
		Error: fmt.Sprintf("unable to access the path: %v", err),
	}
	result.Failed = append(result.Failed, fileInfo)
	c.logger.Error(fmt.Sprintf("delete failed: %s - %v", absPath, err))
	return
}

// shouldDelete 判断是否应该删除
func (c *FileCleaner) shouldDelete(fileInfo config.FileInfo) bool {
	// 自动模式直接删除
	if c.config.CleanAuto {
		return true
	}

	// 模拟运行模式直接"删除"
	if c.config.CleanDryRun {
		return true
	}

	// 不需要确认时直接删除
	if !c.config.CleanConfirm {
		return true
	}

	// 询问用户确认
	return c.askForDeletion(fileInfo.Path)
}

// deletePath 删除路径
func (c *FileCleaner) deletePath(fileInfo config.FileInfo) error {
	// 模拟运行模式，不实际删除
	if c.config.CleanDryRun {
		return nil
	}

	if fileInfo.IsDir {
		return os.RemoveAll(fileInfo.Path)
	} else {
		return os.Remove(fileInfo.Path)
	}
}

// askForDeletion 询问用户是否删除
func (c *FileCleaner) askForDeletion(path string) bool {
	reader := bufio.NewReader(os.Stdin)

	for {
		fmt.Printf("delete '%s'? [y/n]: ", path)
		response, err := reader.ReadString('\n')
		if err != nil {
			c.logger.Error("read user input failed: " + err.Error())
			return false
		}

		response = strings.TrimSpace(strings.ToLower(response))

		switch response {
		case "y", "yes":
			return true
		case "n", "no", "":
			return false
		default:
			fmt.Println("please input 'y' or 'n'")
		}
	}
}
